;(function ($, window, document, undefined) {

// Standard plugin vars
var plugin_name = 'dragit';
var defaults = {
	prepend: 'dragit_',
	startEvents: 'touchstart mousedown',
	dropEvents: 'touchend touchcancel touchup touchleave mouseup',
	dragEvents: 'touchmove mousemove',
	dragPreventDefault: false,
	drag: null,
	stop: null,
	start: null
};

// Other vars
var $body = $('body');
var return_false = function() { return false; };

// Constructor
var Plugin = function(element, options) {
	// Standard
	var me = this;
	this.element = $(element);
	this.options = $.extend({}, defaults, options) ;
	this._defaults = defaults;
	this._name = plugin_name;

	// Other
	this.lastX = null;
	this.lastY = null;
	this.OldUserSelect = null;
	this.moving = false;
	this.props_default = {
		elementStartX: null,
		elementStartY: null,
		startX: null,
		startY: null,
		deltaX: 0,
		deltaY: 0,
		totalX: 0,
		totalY: 0
	};
	this.props = null;

	this.drag = function (event) {
		if ( me.options.dragPreventDefault ) event.preventDefault();

		if ( event.originalEvent.touches ) {
			event.pageX = event.originalEvent.touches[0].clientX;
			event.pageY = event.originalEvent.touches[0].clientY;
		}

		me.props.deltaX = event.pageX - me.lastX;
		me.props.deltaY = event.pageY - me.lastY;
		me.props.totalX = event.pageX - me.props.startX;
		me.props.totalY = event.pageY - me.props.startY;
		me.lastX = event.pageX;
		me.lastY = event.pageY;

		me.element.trigger(me.options.prepend + 'drag', me.props);
	};

	this.drop = function (event) {
		$body
			.unbind(me.options.dragEvents, me.drag)
			.unbind(me.options.dropEvents, me.drop)
			.unbind('mouseleave', me.drop);

		$body.css({UserSelect: me.OldUserSelect});

		if ($.browser.msie) {
			$body
				.unbind('dragstart', return_false)
				.unbind('selectstart', return_false);
		}

		me.moving = false;

		me.element.trigger(me.options.prepend + 'drop', me.props);
	};

	this.start = function(event) {
		if ( me.moving ) return true;
		me.moving = true;

		if ( event.originalEvent.touches ) {
			event.pageX = event.originalEvent.touches[0].clientX;
			event.pageY = event.originalEvent.touches[0].clientY;
		}

		var el_pos = me.element.position();

		me.props = $.extend(me.props_default, {
			startX: event.pageX,
			startY: event.pageY,
			elementStartX: el_pos.left,
			elementStartY: el_pos.top
		});

		me.lastX = event.pageX;
		me.lastY = event.pageY;

		me.OldUserSelect = $body.css('UserSelect');

		if ( $.browser.msie ) {
			$body
				.bind('dragstart', return_false)
				.bind('selectstart', return_false);
		}

		$body
			.css({UserSelect: 'none'})
			.bind(me.options.dragEvents, me.drag)
			.bind(me.options.dropEvents, me.drop)
			.bind('mouseleave', me.drop);

		me.element.trigger(me.options.prepend + 'start', me.props);
	};

	this.init();
}

Plugin.prototype.init = function () {
	this.element
		.bind(this.options.startEvents, this.start);
};

$.fn[plugin_name] = function (options) {
	return this.each(function () {
		if (!$.data(this, 'plugin_' + plugin_name)) {
			$.data(this, 'plugin_' + plugin_name, new Plugin(this, options));
		}
		// Maybe have something here to update options
	});
};

})(jQuery, window, document);